/*********************************************************************
 * INCLUDES
 */
#include "i2c.h"

static void IIC_SCL_0(void);
static void IIC_SCL_1(void);
static void IIC_SDA_0(void);
static void IIC_SDA_1(void);
static bool SCL_STATE_HIGHT = FALSE;// SCL高电平
static bool SDA_STATE_HIGHT = FALSE;// SDA高电平

#define IIC_DTCY_2

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief I2C驱动初始化，采用模拟IO的方式实现
 @param 无
 @return 无
*/
void IIC_Init(void)
{
    delay_config_iic();

    rcu_periph_clock_enable(IIC_SCL_CLK);
    rcu_periph_clock_enable(IIC_SDA_CLK);

    IIC_SCL_1();
    IIC_SDA_1();
    
    gpio_mode_set(IIC_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, IIC_SCL_PIN);
    gpio_output_options_set(IIC_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, IIC_SCL_PIN);

    gpio_mode_set(IIC_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, IIC_SDA_PIN);
    gpio_output_options_set(IIC_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, IIC_SDA_PIN);

}

/**
 @brief CPU发起I2C总线启动信号
 @param 无
 @return 无
*/
void IIC_Start(void)
{
    if(!SDA_STATE_HIGHT) {
        IIC_SDA_1();
        delay_iic();
    }
    if(!SCL_STATE_HIGHT) {
        IIC_SCL_1();
        delay_iic();
    }
    delay_us(1);
    IIC_SDA_0();            // 当SCL高电平时，SDA出现一个下跳沿表示I2C总线启动信号
    delay_iic();    
    //IIC_SCL_0();            // 钳住I2C总线，准备发送或接收数据 
}   

/**
 @brief CPU发起I2C总线停止信号
 @param 无
 @return 无
*/
void IIC_Stop(void)
{
    // IIC_SCL_0();
    // IIC_SDA_0();
    if(!SCL_STATE_HIGHT || !SDA_STATE_HIGHT){
        delay_iic();
    }
    if(!SCL_STATE_HIGHT){
        IIC_SCL_1();
        delay_iic();
    }
    if(!SDA_STATE_HIGHT) {
        IIC_SDA_1();            // 当SCL高电平时，SDA出现一个上跳沿表示I2C总线停止信号       
        delay_iic();
    }
}

/**
 @brief CPU向I2C总线设备发送8bit数据
 @param ucByte -[in] 等待发送的字节
 @return 无
*/  
void IIC_SendByte(uint8_t ucByte)
{                        
    uint8_t i;
    
    if(SCL_STATE_HIGHT) {
        IIC_SCL_0();            // 拉低时钟开始数据传输
    }
    
    for(i = 0; i < 8; i++)
    {              
        if(ucByte & 0x80)   
        {            
            delay_iic();
            IIC_SDA_1();
        }
        else
        {
            IIC_SDA_0();
            delay_iic();
        }
        ucByte <<= 1;   
        IIC_SCL_1();
        delay_iic();
        IIC_SCL_0();
        // IIC_SCL_0();
        // IIC_SCL_0();
        // IIC_SCL_0();
        // delay_iic();
    }
} 

/**
 @brief CPU从I2C总线设备读取8bit数据
 @param 无
 @return 读到的数据
*/ 
uint8_t IIC_ReadByte(bool ack)
{
    uint8_t i = 0;
    uint8_t value = 0;
    
    if(!SDA_STATE_HIGHT) IIC_SDA_1();                // CPU释放SDA总线

    for(i = 0; i < 8; i++)
    {
        value <<= 1;
        IIC_SCL_1();
        delay_iic();
        if(IIC_SDA_READ())
        {
            value++;
        }            
        IIC_SCL_0(); 
        delay_iic();
    }                   
    if(ack)
        IIC_Ack();
    else
        IIC_NAck();

    return value;
}

bool IIC_WriteSlave(uint8_t slave_addr, uint8_t *data, uint8_t len)
{
    bool success = FALSE;
    do {
        IIC_Start();
        IIC_SendByte(slave_addr << 1);
        if (IIC_WaitAck())
            break;
        while (len--) {
            IIC_SendByte(*data++);
            if (IIC_WaitAck())
                break;
        }
        IIC_Stop();
        success = TRUE;
    } while(0);
    return success;
}

bool IIC_ReadSlave(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len)
{
    bool success = FALSE;
    do {
        IIC_Start();
        IIC_SendByte(slave_addr << 1);
        if (IIC_WaitAck())
            break;
        IIC_SendByte(data);
        if (IIC_WaitAck())
            break;
        IIC_Start();
        IIC_SendByte(slave_addr << 1 | 1);// Slave address + read
        if (IIC_WaitAck())
            break;
        while(len) {
            bool ack = TRUE;
            if(len == 1){
                ack = FALSE;
            }
            *buf = IIC_ReadByte(ack);
            buf++;
            len--;
        }
        success = TRUE;
    } while(0);
    IIC_Stop();
    return success;
}

/**
 @brief CPU产生一个时钟，并读取器件的ACK应答信号
 @param 无
 @return 返回0表示正确应答，1表示无器件响应
*/
uint8_t IIC_WaitAck(void)
{
    uint8_t result = 0; 

    IIC_SDA_1();            // CPU释放SDA总线
    IIC_SCL_1();            // CPU驱动SCL = 1, 此时器件会返回ACK应答
    delay_iic();
    if(IIC_SDA_READ())
    {
        result = 1;
    }
    else
    {
        result = 0;
    }
    IIC_SDA_0();
    IIC_SCL_0();

    return result;  
} 

/**
 @brief CPU产生一个ACK信号
 @param 无
 @return 无
*/
void IIC_Ack(void)
{
    IIC_SDA_0();            // CPU驱动SDA = 0
    delay_iic();
    IIC_SCL_1();            // CPU产生1个时钟
    delay_iic();
    IIC_SCL_0();
    delay_iic();
    IIC_SDA_1();            // CPU释放SDA总线
}

/**
 @brief CPU产生1个NACK信号
 @param 无
 @return 无
*/    
void IIC_NAck(void)
{
    IIC_SDA_1();            // CPU驱动SDA = 1
    delay_iic();
    IIC_SCL_1();            // CPU产生1个时钟
    delay_iic();
    IIC_SCL_0();
    delay_iic();
}

/**
 @brief 检测I2C总线设备，CPU向发送设备地址，然后读取设备应答来判断该设备是否存在
 @param address -[in] 设备的I2C总线地址+读写控制bit（0 = w， 1 = r)
 @return 0 - 表示正确， 1 - 表示未探测到
*/  
uint8_t IIC_CheckDevice(uint8_t address)
{
    uint8_t ucAck;

    IIC_Init();             // 初始化I2C
    delay_iic();
    IIC_Start();            // 发送启动信号
    IIC_SendByte(address << 1);  // 设备的I2C总线地址+读写控制bit（0 = w， 1 = r)
    ucAck = IIC_WaitAck();  // 检测设备的ACK应答
    IIC_Stop();             // 发送停止信号

    return ucAck;
}

static void IIC_SCL_0(void){
    if (SCL_STATE_HIGHT) {
        gpio_bit_reset(IIC_SCL_PORT, IIC_SCL_PIN);
        SCL_STATE_HIGHT = FALSE;
    }
}

static void IIC_SCL_1(void){
    if (!SCL_STATE_HIGHT) {
        gpio_bit_set(IIC_SCL_PORT, IIC_SCL_PIN);
        SCL_STATE_HIGHT = TRUE;
    }
}

static void IIC_SDA_0(void){
    if (SDA_STATE_HIGHT) {
        gpio_bit_reset(IIC_SDA_PORT, IIC_SDA_PIN);
        SDA_STATE_HIGHT = FALSE;
    }
}

static void IIC_SDA_1(void){
    if (!SDA_STATE_HIGHT) {
        gpio_bit_set(IIC_SDA_PORT, IIC_SDA_PIN);
        SDA_STATE_HIGHT = TRUE;
    }
}

/****************************************************END OF FILE****************************************************/
